<template>
	<div class="editor-container">
		<Toolbar :editor="editorRef" :mode="mode" />
		<Editor
			:mode="mode"
			:defaultConfig="state.editorConfig"
			:style="{ height }"
			v-model="state.editorVal"
			@onCreated="handleCreated"
			@onChange="handleChange"
		/>
	</div>
</template>

<script setup lang="ts" name="wngEditor">
// https://www.wangeditor.com/v5/for-frame.html#vue3
import '@wangeditor/editor/dist/css/style.css';
import { reactive, shallowRef, watch, onBeforeUnmount } from 'vue';
import { IDomEditor, IEditorConfig } from '@wangeditor/editor';
import { Toolbar, Editor } from '@wangeditor/editor-for-vue';
import { useCommonApi } from '/@/api/common';
import { ElMessage } from 'element-plus';
import axios from 'axios';

// 定义父组件传过来的值
const props = defineProps({
	// 是否禁用
	disable: {
		type: Boolean,
		default: () => false,
	},
	// 内容框默认 placeholder
	placeholder: {
		type: String,
		default: () => '请输入内容...',
	},
	// https://www.wangeditor.com/v5/getting-started.html#mode-%E6%A8%A1%E5%BC%8F
	// 模式，可选 <default|simple>，默认 default
	mode: {
		type: String,
		default: () => 'default',
	},
	// 高度
	height: {
		type: String,
		default: () => '310px',
	},
	// 双向绑定，用于获取 editor.getHtml()
	getHtml: String,
	// 双向绑定，用于获取 editor.getText()
	getText: String,
});

// 定义子组件向父组件传值/事件
const emit = defineEmits(['update:getHtml', 'update:getText']);

// 定义变量内容
const editorRef = shallowRef();
interface StateSchema {
	editorConfig: Partial<IEditorConfig>;
	editorVal: any;
}
type InsertFnType = (url: string, alt: string, href: string) => void;

const random_string = (len = 32) => {
	const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
	const maxPos = chars.length;
	let pwd = '';
	for (let i = 0; i < len; i++) {
		pwd += chars.charAt(Math.floor(Math.random() * maxPos));
	}
	return pwd;
};
const get_suffix = (filename: string) => {
	const pos = filename.lastIndexOf('.');
	let suffix = '';
	if (pos != -1) {
		suffix = filename.substring(pos);
	}
	return suffix;
};

const calculate_object_name = (dir: string, filename: string) => {
	let suffix = get_suffix(filename);
	return dir + random_string(10) + suffix;
};

const beforeUpload = async (rawFile: File) => {
	const { name } = rawFile;
	//以下处理一定要加，不然会出现问题1
	try {
		const { result: data } = await useCommonApi().oss();
		// fileName.value = name;
		// actionUrl.value = data.host;
		// basedata.value =

		return {
			url: data.host,
			data: {
				key: calculate_object_name(data.dir, name),
				success_action_status: '200',
				policy: data.policy,
				OSSAccessKeyId: data.accessid,
				signature: data.signature,
			},
		};
	} catch (err) {
		return Promise.reject(false);
	}
};

const handleUpload = async (file: File, info: any) => {
	const { url, data: basedata } = info;
	let formdata = new FormData();
	formdata.append('OSSAccessKeyId', basedata.OSSAccessKeyId);
	formdata.append('success_action_status', basedata.success_action_status);
	formdata.append('policy', basedata.policy);
	formdata.append('Signature', basedata.signature);
	formdata.append('key', basedata.key);
	// formdata.append('callback',basedata.value.callback);
	formdata.append('file', file); //file 一定要在 key 之后 不然会报错

	await axios({
		url: url,
		method: 'post',
		data: formdata,
		headers: {
			'Content-Type': 'multipart/form-data',
		},
	});
	return import.meta.env.VITE_OSS_URL + '/' + basedata.key;
};

const state = reactive<StateSchema>({
	editorConfig: {
		placeholder: props.placeholder,
		MENU_CONF: {
			uploadImage: {
				server: '/api/upload',
				customUpload: async (file: File, insertFn: InsertFnType) => {
					const info = await beforeUpload(file);
					const url = await handleUpload(file, info);
					insertFn(url, '', '');
				},
			},
		},
	},
	editorVal: props.getHtml,
});

// 编辑器回调函数
const handleCreated = (editor: IDomEditor) => {
	editorRef.value = editor;
};
// 编辑器内容改变时
const handleChange = (editor: IDomEditor) => {
	emit('update:getHtml', editor.getHtml());
	emit('update:getText', editor.getText());
};
// 页面销毁时
onBeforeUnmount(() => {
	const editor = editorRef.value;
	if (editor == null) return;
	editor.destroy();
});
// 监听是否禁用改变
// https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I
watch(
	() => props.disable,
	(bool) => {
		const editor = editorRef.value;
		if (editor == null) return;
		bool ? editor.disable() : editor.enable();
	},
	{
		deep: true,
	}
);
// 监听双向绑定值改变，用于回显
watch(
	() => props.getHtml,
	(val) => {
		state.editorVal = val;
	},
	{
		deep: true,
	}
);
</script>
